package com.uexUploader;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.UUID;

import org.json.JSONArray;
import org.json.JSONObject;
import org.zywx.wbpalmstar.base.BUtility;
import org.zywx.wbpalmstar.engine.EBrowserView;
import org.zywx.wbpalmstar.engine.universalex.EUExBase;
import org.zywx.wbpalmstar.engine.universalex.EUExCallback;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;

public class EUExUploader extends EUExBase {

	public static final String tag = "uexUploader_";
	private static final String F_CALLBACK_NAME_UPLOADSTATUS = "uexUploader.onStatus";
	private static final String F_CALLBACK_NAME_CREATEUPLOADER = "uexUploader.cbCreateUploader";

	public static final int F_FILE_TYPE_CREATE = 0;
	public static final int F_FILE_TYPE_UPLOAD = 1;

	static final String SCRIPT_HEADER = "javascript:";

	private static final int TIME_OUT = 5 * 60 * 1000; // 超时时间
	private static final String CHARSET = "utf-8"; // 设置编码
	private HashMap<Integer, EUExFormFile> objectMap;

	public EUExUploader(Context context, EBrowserView inParent) {
		super(context, inParent);
		objectMap = new HashMap<Integer, EUExFormFile>();
	}

	public void createUploader(String[] parm) {

		if (parm.length != 2) {
			return;
		}
		String inOpCode = parm[0], inTargetAddress = parm[1];
		if (!BUtility.isNumeric(inOpCode)) {
			return;
		}
		if (objectMap.containsKey(Integer.parseInt(inOpCode))) {
			jsCallback(F_CALLBACK_NAME_CREATEUPLOADER, Integer.parseInt(inOpCode), EUExCallback.F_C_INT, EUExCallback.F_C_FAILED);
			return;
		}
		if (inTargetAddress == null || inTargetAddress.length() == 0 || !inTargetAddress.startsWith(BUtility.F_HTTP_PATH)) {
			jsCallback(F_CALLBACK_NAME_CREATEUPLOADER, Integer.parseInt(inOpCode), EUExCallback.F_C_INT, EUExCallback.F_C_FAILED);
			return;
		}
		objectMap.put(Integer.parseInt(inOpCode), new EUExFormFile(inTargetAddress, null));
		jsCallback(F_CALLBACK_NAME_CREATEUPLOADER, Integer.parseInt(inOpCode), EUExCallback.F_C_INT, EUExCallback.F_C_SUCCESS);
	}

	public void closeUploader(String[] parm) {
		String inOpCode = parm[0];
		if (!BUtility.isNumeric(inOpCode)) {
			return;
		}
		objectMap.remove(Integer.parseInt(inOpCode));

	}

	public void uploadFile(String[] parm) {
		if (parm.length < 3) {
			return;
		}

		final String inOpCode = parm[0];
		String inFilePath = parm[1];
		final String inInputName = parm[2];
		final String jsonData = parm[3];
		int inCompress = 0;
		if (parm.length == 5) {
			inCompress = Integer.parseInt(parm[4]);
		}
		float inWith = -1;
		if (parm.length == 6) {
			inCompress = Integer.parseInt(parm[4]);
			if (!TextUtils.isEmpty(parm[5])) {
				inWith = Float.valueOf(parm[5]).floatValue();
			}
		}
		if (!BUtility.isNumeric(inOpCode)) {
			return;
		}
		if (inFilePath == null || inFilePath.length() == 0) {
			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
					+ EUExCallback.F_C_UpLoadError + ")}";
			onCallback(js);
			return;

		}
		if (mBrwView.getCurrentWidget() == null) {
			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
					+ EUExCallback.F_C_UpLoadError + ")}";
			onCallback(js);
			return;
		}
		inFilePath = BUtility.makeRealPath(BUtility.makeUrl(mBrwView.getCurrentUrl(), inFilePath), mBrwView.getCurrentWidget().m_widgetPath, mBrwView.getCurrentWidget().m_wgtType);
		if (inFilePath.startsWith(BUtility.F_FILE_SCHEMA)) {
			inFilePath = inFilePath.substring(BUtility.F_FILE_SCHEMA.length());
		}
		final EUExFormFile formFile = objectMap.get(Integer.parseInt(inOpCode));
		if (formFile.state == F_FILE_TYPE_CREATE) {
			formFile.state = F_FILE_TYPE_UPLOAD;
		} else {
			return;
		}
		try {

			if (inFilePath.startsWith("/")) {
				File file = new File(inFilePath);
				if (!file.exists()) {
					String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
							+ EUExCallback.F_C_UpLoadError + ")}";
					onCallback(js);
					return;
				}
				InputStream inputSteam = null;
				if (inCompress > 0) {
					try {
						inputSteam = compress(mContext, inFilePath, inCompress, inWith);
					} catch (OutOfMemoryError e) {
						String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
								+ EUExCallback.F_C_UpLoadError + ")}";
						onCallback(js);
						e.printStackTrace();
						return;
					} catch (IOException e) {
						String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
								+ EUExCallback.F_C_UpLoadError + ")}";
						onCallback(js);
						e.printStackTrace();
						return;
					}

				} else {
					inputSteam = new FileInputStream(file);
				}

				formFile.setInputStream(inputSteam);
				formFile.m_filname = file.getName();
			} else {
				InputStream inputSteam = null;
				if (inCompress > 0) {
					try {
						inputSteam = compress(mContext, inFilePath, inCompress, inWith);
					} catch (OutOfMemoryError e) {
						String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
								+ EUExCallback.F_C_UpLoadError + ")}";
						onCallback(js);
						e.printStackTrace();
						return;
					} catch (IOException e) {
						String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
								+ EUExCallback.F_C_UpLoadError + ")}";
						onCallback(js);
						e.printStackTrace();
						return;
					}
				} else {
					inputSteam = mContext.getAssets().open(inFilePath);
				}
				formFile.setInputStream(inputSteam);
				formFile.m_filname = inFilePath.substring(inFilePath.lastIndexOf("/") + 1);
			}

			final UploadPercentage uploadPercentage = new UploadPercentage();

			new Thread("SoTowerMobile-uexUpload") {
				public void run() {
					Uploader(formFile, uploadPercentage, Integer.parseInt(inOpCode), inInputName, jsonData);
				}
			}.start();
		} catch (Exception e) {
			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
					+ EUExCallback.F_C_UpLoadError + ")}";
			onCallback(js);
			e.printStackTrace();
		}
	}

	private String Uploader(EUExFormFile formFile, UploadPercentage uploadPercentage, int inOpCode, String inInputName, String jsonData) {

		InputStream is = null;
		DataOutputStream outStream = null;
		HttpURLConnection conn = null;

		try {

			if (formFile != null) {
				if (formFile.m_inputStream == null) {
					String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
							+ EUExCallback.F_C_UpLoadError + ")}";
					onCallback(js);
					return null;
				}
				if (inInputName == null || inInputName.length() == 0) {
					inInputName = "file";
				}
				String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
				String PREFIX = "--", LINE_END = "\r\n";
				String CONTENT_TYPE = "multipart/form-data"; // 内容类型

				URL url = new URL(formFile.getM_targetAddress());
				conn = (HttpURLConnection) url.openConnection();
				String cookie = getCookie(formFile.getM_targetAddress());
				if (null != cookie) {
					conn.setRequestProperty("Cookie", cookie);
				}
				conn.setReadTimeout(TIME_OUT);
				conn.setConnectTimeout(TIME_OUT);
				conn.setDoInput(true); // 允许输入流
				conn.setDoOutput(true); // 允许输出流
				conn.setUseCaches(false); // 不允许使用缓存
				conn.setRequestMethod("POST"); // 请求方式
				conn.setRequestProperty("Charset", CHARSET); // 设置编码
				conn.setRequestProperty("connection", "keep-alive");
				conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

				/**
				 * 当文件不为空，把文件包装并且上传
				 */
				DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
				StringBuffer sb = new StringBuffer();
				sb.append(PREFIX);
				sb.append(BOUNDARY);
				sb.append(LINE_END);
				/**
				 * 这里重点注意： name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
				 * filename是文件的名字，包含后缀名的 比如:abc.png
				 */
				if (jsonData.length() > 0) {
					JSONArray arr = new JSONArray(jsonData);
					for (int i = 0; i < arr.length(); i++) {
						JSONObject temp = (JSONObject) arr.get(i);
						String name = temp.getString("name");
						String val = temp.getString("val");
						sb.append("Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n" + val + "");
						sb.append(LINE_END);
						sb.append(PREFIX);
						sb.append(BOUNDARY);
						sb.append(LINE_END);
					}
				}

				sb.append("Content-Disposition: form-data; name=\"" + inInputName + "\"; filename=\"" + formFile.m_filname + "\"" + LINE_END);
				if (formFile.m_filname.indexOf("jpg") > 0 || formFile.m_filname.indexOf("png") > 0 || formFile.m_filname.indexOf("gif") > 0
						|| formFile.m_filname.indexOf("jpeg") > 0) {
					sb.append("Content-Type: image/*" + LINE_END);
				} else {
					sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END);
				}

				sb.append(LINE_END);
				dos.write(sb.toString().getBytes());
				is = formFile.m_inputStream;
				// int l;
				int upload = 0;
				int fileSize = is.available();
				uploadPercentage.setFileSize(fileSize, inOpCode);
				byte[] bytes = new byte[4096];
				int len = 0;
				try {
					while ((len = is.read(bytes)) != -1) {
						dos.write(bytes, 0, len);
						upload += len;
						uploadPercentage.sendMessage(upload);
					}
				} catch (OutOfMemoryError e) {
					String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
							+ EUExCallback.F_C_UpLoadError + ")}";
					onCallback(js);
					return null;
				}

				dos.write(LINE_END.getBytes());
				byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
				dos.write(end_data);

				int res = conn.getResponseCode();

				if (res == 200) {
					String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + uploadPercentage.fileSize + ","
							+ 100 + "," + "null," + EUExCallback.F_C_UpLoading + ")}";
					onCallback(js);
					is = conn.getInputStream();
					int ch;
					StringBuilder b = new StringBuilder();
					while ((ch = is.read()) != -1) {
						b.append((char) ch);
					}
					js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + uploadPercentage.fileSize + "," + 100
							+ ",'" + BUtility.transcoding(b.toString()) + "'," + EUExCallback.F_C_FinishUpLoad + ")}";
					onCallback(js);
				} else {
					String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
							+ EUExCallback.F_C_UpLoadError + ")}";
					onCallback(js);
				}

				is.close();
				dos.flush();
				dos.close();
				formFile.m_isUpLoaded = true;
			}

		} catch (MalformedURLException e) {
			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
					+ EUExCallback.F_C_UpLoadError + ")}";
			onCallback(js);
			e.printStackTrace();
		} catch (Exception e) {
			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + inOpCode + "," + 0 + "," + 0 + "," + "null,"
					+ EUExCallback.F_C_UpLoadError + ")}";
			onCallback(js);
			e.printStackTrace();
		} finally {

			try {
				if (is != null) {
					is.close();
				}
				if (outStream != null) {
					outStream.close();
				}
				if (conn != null) {
					conn.disconnect();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			is = null;
			outStream = null;
			conn = null;
		}

		return null;
	}

	public class UploadPercentage {
		int fileSize;
		int opCode = 0;
		String uploadPercentage = null;
		String callBack = null;
		DecimalFormat df = new DecimalFormat();

		public void setFileSize(int inFileSize, int inOpCode) {
			fileSize = inFileSize;
			df.setMaximumFractionDigits(2);
			df.setMinimumFractionDigits(0);
			opCode = inOpCode;
		}

		public void sendMessage(int msg) {
			String percentage = "0";
			if (fileSize * 100 < 0) {
				percentage = df.format(msg / (fileSize / 100));
			} else {
				percentage = df.format(msg * 100 / fileSize);
			}

			String js = SCRIPT_HEADER + "if(" + F_CALLBACK_NAME_UPLOADSTATUS + "){" + F_CALLBACK_NAME_UPLOADSTATUS + "(" + opCode + "," + fileSize + "," + percentage + ","
					+ "null," + EUExCallback.F_C_UpLoading + ")}";
			onCallback(js);

		}
	}

	@Override
	protected boolean clean() {
		return false;
	}

	private InputStream compress(Context m_eContext, String path, int compress, float with) throws OutOfMemoryError, IOException {
		FileDescriptor fileDescriptor = null;
		boolean isRes = false;
		if (!path.startsWith("/")) {
			AssetFileDescriptor assetFileDescriptor = m_eContext.getAssets().openFd(path);
			fileDescriptor = assetFileDescriptor.getFileDescriptor();
			isRes = true;
		} else {
			FileInputStream fis = new FileInputStream(new File(path));
			fileDescriptor = fis.getFD();
		}
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		Bitmap source = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
		if (options.outHeight <= 0 || options.outWidth <= 0) {
			if (isRes) {
				return m_eContext.getAssets().open(path);
			} else {
				return new FileInputStream(new File(path));
			}

		}

		int quality = 0;
		if (compress == 1) {
			quality = 100;
		} else if (compress == 2) {
			quality = 75;
		} else if (compress == 3) {
			quality = 50;
		} else {
			quality = 25;
		}

		float max = with == -1 ? 640 : with;
		float src_w = options.outWidth;
		float scaleRate = 1;

		scaleRate = src_w / max;

		scaleRate = scaleRate > 1 ? scaleRate : 1;

		if (scaleRate != 1) {
			Bitmap dstbmp = null;
			ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
			options.inSampleSize = (int) scaleRate;
			options.inJustDecodeBounds = false;
			options.inInputShareable = true;
			options.inPurgeable = true;
			options.inPreferredConfig = Config.RGB_565;// 会失真，缩略图失真没事^_^

			source = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
			if (source != null) {
				int srcWidth = source.getWidth();
				int srcHeight = source.getHeight();
				final float sacleRate = max / (float) srcWidth;
				final int destWidth = (int) (srcWidth * sacleRate);
				final int destHeight = (int) (srcHeight * sacleRate);
				dstbmp = Bitmap.createScaledBitmap(source, destWidth, destHeight, false);
				if (source != null && !source.isRecycled()) {
					source.recycle();
				}
				if (dstbmp.compress(CompressFormat.JPEG, quality, baos)) {
					if (dstbmp != null && !dstbmp.isRecycled()) {
						dstbmp.recycle();
					}
					return new ByteArrayInputStream(baos.toByteArray());
				} else {
					baos.close();
					if (isRes) {
						return m_eContext.getAssets().open(path);
					} else {
						return new FileInputStream(new File(path));
					}
				}
			} else {
				if (isRes) {
					return m_eContext.getAssets().open(path);
				} else {
					return new FileInputStream(new File(path));
				}
			}

		} else {
			if (isRes) {
				return m_eContext.getAssets().open(path);
			} else {
				return new FileInputStream(new File(path));
			}
		}

	}
}
